#define _CRT_SECURE_NO_WARNINGS 1

// 自定义类型：联合和枚举
// 像结构体一样，联合体也是由一个或者多个成员构成，这些成员可以是不同的类型
// 但是编译器只为最大的成员分配足够的内存空间
// 联合体的特点是所有成员共用同一块内存空间，所以联合体也叫做：共用体
// 给联合体其中一个成员赋值，其他成员的值也跟着变化

// 结构体：struct
// 联合体：union
// 联合体的大小至少是最大成员的大小
// 当最大成员大小不是最大对齐数的整数倍时候，就要对齐到最大对齐数的整数倍
// 如果是数组，按照元素类型来判断最大对齐数

//#include <stdio.h>
//
//union u
//{
//	char c;
//	int u;
//};
//
//int main()
//{
//	union u uu;
//
//	printf("%zd\n", sizeof(uu));
//	printf("%p\n", &uu);
//	printf("%p\n", &(uu.c));
//	printf("%p\n", &(uu.u));
//
//	return 0;
//}

// 联合体也有内存对齐
//#include <Stdio.h>
//
//union Un1
//{
//	char c[5]; // 5
//	// 1 0 1
//	int i; // 4 8 4
//};
//
//union Un2
//{
//	short c[7];
//	int i;
//};
//
//int main()
//{
//	printf("%zd\n", sizeof(union Un1)); // 8
//	printf("%zd\n", sizeof(union Un2)); // 16
//
//	return 0;
//}

// 联合体的使用场景
struct gift_list
{
	// 公共属性
	int stock_number; // 库存量
	double price; // 定价
	int item_type; // 商品类型

	// 特殊属性
	char title[20]; // 书名
	char author[20]; // 作者
	int num_pages; // 页数

	char design[30]; // 设计
	int colors; // 颜色
	int sizes; // 尺寸
};
// 这样虽然简单，但是结构体的大小偏大，浪费内存
// 所以可以单独把公共属性写出来，剩余属于各种商品本身的属性使用联合体起来，一定程度上节省了内存

//struct gift_list
//{
//	int stock_number; // 库存量
//	double price; // 定价
//	int item_type; // 商品类型
//
//	union {
//		struct
//		{
//			char title[20]; // 书名
//			char author[20]; // 作者
//			int num_pages; // 页数
//		}book;
//		struct
//		{
//			char design[30]; // 设计
//		}mug;
//		struct
//		{
//			char design[30]; // 设计
//			int colors; // 颜色
//			int sizes; // 尺寸
//		}shirt;
//	}item;
//};

//#include <stdio.h>
//
//union U
//{
//	int n; // 4
//	struct S
//	{
//		char c1;
//		char c2;
//		char c3;
//		char c4;
//	}s; // 4
//};
//
//int main()
//{
//	union U u = { 0 };
//	u.n = 0x11223344;
//
//	// 也可以看出来是小端
//	printf("%x %x %x %x\n", u.s.c1, u.s.c2, u.s.c3, u.s.c4);
//
//	return 0;
//}

// 以下代码也可以判断机器是大端还是小端
//#include <stdio.h>
//
//int check_sys()
//{
//	// 方法一：
//	//int n = 1;
//	//return *(char*)&n;
//
//	// 方法二：
//	union
//	{
//		char c;
//		int i;
//	}u;
//	u.i = 1;
//	return u.c;
//}
//
//int main()
//{
//	int ret = check_sys();
//
//	if (ret == 1) printf("小端\n");
//	else printf("大端\n");
//
//	return 0;
//}

// 枚举的关键字
// {}中的内容是枚举类型的可能取值，也叫枚举常量
// 这些可能取值都是有值的，默认从0开始，依次递增1，当然在声明枚举类型的时候也可以赋初值

//#include <stdio.h>
//
//enum Sex
//{
//	// 这里列举枚举enum Sex的可能取值
//	// 这些可能取值是常量，也叫枚举常量
//	MALE,
//	FEMALE,
//	SECRET
//};
//
//int main()
//{
//	printf("%d\n", MALE);
//	printf("%d\n", FEMALE);
//	printf("%d\n", SECRET);
//
//	enum Sex s = MALE;
//	s = FEMALE;
//
//	return 0;
//}

// 枚举的好处
// 1.增加代码的可读性和可维护性
// 2.和#define定义的标识符比较枚举有类型检查，更加严谨
// 3.便于调试，预处理阶段会删除#define定义的符号
// 4.使用方便，一次可以定义多个常量
// 5.枚举常量是遵循作用域规则的，枚举声明在函数内，只能在函数内使用

// 是否可以用整数给枚举变量赋值呢？
// 在C语言中是可以的，但是在C++是不行的，C++的类型检查比较严格
